﻿using System;
using System.Collections.Generic;
using System.Drawing.Design;
using System.Linq;
using System.Windows.Forms.Design;
using devtm.Editor.TypeSelector;
using DslModeling = global::Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling;
using System.Windows.Forms;
using System.Reflection;

namespace devtm.AutoMapper
{
    public class ListeMemberEditor : UITypeEditor
    {

        protected DslModeling.Store Store;
        protected ItemMap Instance;

        /*
        /// <summary>
        /// Edits the specified object's value using the editor style indicated by the <see cref="M:System.Drawing.Design.UITypeEditor.GetEditStyle"/> method.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that can be used to gain additional context information.</param>
        /// <param name="provider">An <see cref="T:System.IServiceProvider"/> that this editor can use to obtain services.</param>
        /// <param name="value">The object to edit.</param>
        /// <returns>
        /// The new value of the object. If the value of the object has not changed, this should return the same object it was passed.
        /// </returns>
        public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, IServiceProvider provider, object value1)
        {

            object value2 = null;

            IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
            if (edSvc != null)
            {

                Instance = context.Instance as ItemMap;
                Store = Instance.Store;
                Mapper mapper = GetMapper(context);
                TypeElement typeElement = GetTypeElement(context, mapper);


                ListBox control = new ListBox();
                control.DisplayMember = "Name";
                control.ValueMember = "AssemblyQualifiedName";
                var datas = GetMembers(typeElement.Type).OrderBy(c => c.Name).ToList();
                
                control.DataSource = datas;
                
                control.VisibleChanged +=
                      (object sender, EventArgs e) =>
                      {

                          if (!String.IsNullOrEmpty((string)value1))
                              foreach (MemberInfo item in datas)
                                  if ((value1 as string).Equals(item.Name))
                                      control.SelectedItem = item;

                      };
                


                control.Click +=
                    (object sender, EventArgs e) =>
                    {

                        if (sender != null && (sender as ListBox).SelectedItem != null)
                            try
                            {

                                MemberInfo mm = control.SelectedItem as MemberInfo;
                                value2 = mm.Name;

                                using (Transaction trans = Store.TransactionManager.BeginTransaction("Update Type"))
                                {

                                    if (context.PropertyDescriptor.Name.Contains("Source"))
                                    {
                                        Instance.SourceType = ItemMap.FindTypeName(mm);
                                        MappingHelper.SetInfoTypeSource(Instance, mm.GetTypeFrom());
                                    }
                                    else
                                    {
                                        Instance.TargetType = ItemMap.FindTypeName(mm);
                                        MappingHelper.SetInfoTypeTarget(Instance, mm.GetTypeFrom());
                                    }

                                    trans.Commit();
                                }

                                value1 = value2;
                            }
                            catch (Exception)
                            {

                            }


                        edSvc.CloseDropDown();

                    };

                edSvc.DropDownControl(control);

            }

            return value1;

        }
        */



        public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, IServiceProvider provider, object value)
        {

            IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
            if (edSvc != null)
            {


                bool isSource = context.PropertyDescriptor.Name.Contains("Source");

                Instance = context.Instance as ItemMap;
                Store = Instance.Store;
                Mapper mapper = GetMapper(context);
                TypeElement typeElement = GetTypeElement(context, mapper);

                //ListBox control = new ListBox();
                TreeView control = new TreeView();

                //control.DisplayMember = "Name";
                //control.ValueMember = "AssemblyQualifiedName";

                TreeNode t =
                    isSource
                    ? new TreeNode() { Text = typeElement.Type.Name, Tag = typeElement.Type, ToolTipText = "this" }
                    : new TreeNode() { Text = typeElement.Type.Name };

                GetNodeMembers(typeElement.Type, t);
                control.Nodes.Add(t);
                t.Expand();

                if (isSource)
                    BuildSubProperties(t);

                int indx = 0;
                if (!string.IsNullOrEmpty(value as string))
                {
                    string[] tb = (value as string).Split('.');
                    FindProperty(tb, control, t, ref indx);
                }

                if (isSource)
                    control.BeforeExpand +=
                        (sender, e) =>
                        {
                            BuildSubProperties(e.Node);
                        };

                control.AfterSelect +=
                (sender, e) =>
                {

                    try
                    {

                        MemberInfo mm = control.SelectedNode.Tag as MemberInfo;

                        if (mm == null || value as string == control.SelectedNode.ToolTipText)
                            return;

                        value = control.SelectedNode.ToolTipText;

                        using (Transaction trans = Store.TransactionManager.BeginTransaction("Update Type"))
                        {

                            Instance.NeedMap = MappingHelper.ResolveNeedMap(mm.GetTypeFrom());

                            if (isSource)
                            {
                                Instance.SourceType = ItemMap.FindTypeName(mm);
                                MappingHelper.SetInfoTypeSource(Instance, mm.GetTypeFrom());
                            }
                            else
                            {
                                Instance.TargetType = ItemMap.FindTypeName(mm);
                                MappingHelper.SetInfoTypeTarget(Instance, mm.GetTypeFrom());
                            }

                            trans.Commit();
                        }

                    }
                    catch (Exception)
                    {

                    }


                    if (sender != null)
                        if ((sender as TreeView).SelectedNode != null)
                            edSvc.CloseDropDown();

                };

                edSvc.DropDownControl(control);

            }

            return value;

        }

        private void BuildSubProperties(TreeNode t)
        {
            foreach (TreeNode t2 in t.Nodes)
            {

                if (t2.Nodes.Count > 0)
                    continue;

                Type type = null;
                PropertyInfo p1 = t2.Tag as PropertyInfo;

                if (p1 != null)
                    type = p1.PropertyType;
                else
                    type = (t2.Tag as FieldInfo).FieldType;

                if (type.IsEnum)
                    continue;

                string n = type.FullName;

                if (!NewMapperHelper.types.Contains(n))
                    GetNodeMembers(type, t2);

            }
        }

        private void BuildSubProperty(TreeNode t)
        {

                if (t.Nodes.Count > 0)
                    return;

                Type type = null;
                PropertyInfo p1 = t.Tag as PropertyInfo;

                if (p1 != null)
                    type = p1.PropertyType;
                else
                    type = (t.Tag as FieldInfo).FieldType;

                if (type.IsEnum)
                    return;

                string n = type.FullName;

                if (!NewMapperHelper.types.Contains(n))
                    GetNodeMembers(type, t);

        }

        private void FindProperty(string[] value, TreeView control, TreeNode t, ref int index)
        {

            foreach (TreeNode item in t.Nodes)
            {
         
                if (item.Text == value[index])
                {
                    control.SelectedNode = item;

                    if (index < value.Length - 1)
                    {
                        index++;

                        if (item.Nodes.Count == 0)
                            BuildSubProperty(item);


                        FindProperty(value, control, item, ref index);
                        
                    }
                    return;

                }
            }
        }

      
        private void GetNodeMembers(Type type, TreeNode t)
        {

            foreach (MemberInfo item in type.GetMembers())

                if (item is PropertyInfo || item is FieldInfo)
                {
                    TreeNode t2 = new TreeNode()
                    {
                        Tag = item,
                        Text = item.Name,
                        ToolTipText = GetName(t, item)
                    };
                    t.Nodes.Add(t2);
                }

        }

        private static string GetName(TreeNode t, MemberInfo item)
        {
            if (t.ToolTipText == "this")
                return item.Name;

            return t.Tag != null && !string.IsNullOrEmpty(t.ToolTipText) ? t.ToolTipText + "." + item.Name : item.Name;
        }


        private static Mapper GetMapper(System.ComponentModel.ITypeDescriptorContext context)
        {
            ItemMap p1 = context.Instance as ItemMap;
            return p1.Mapper;
        }

        //private IEnumerable<MemberInfo> GetMembers(Type type)
        //{
        //    foreach (MemberInfo item in type.GetMembers())
        //        if (item is PropertyInfo || item is FieldInfo)
        //            yield return item;
        //}


        public override bool IsDropDownResizable
        {
            get
            {
                return true;
            }
        }

        public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
        {

            

            if (context != null)
            {

                Instance = context.Instance as ItemMap;
                Store = Instance.Store;
                Mapper mapper = GetMapper(context);                
                TypeElement typeElement = GetTypeElement(context, mapper);

                Type type = mapper.MappingModel.FindType(typeElement.AssemblyQualifiedName);

                if (typeElement.Type != null)
                    return UITypeEditorEditStyle.DropDown;

            }

            return UITypeEditorEditStyle.None;
        }

        private static TypeElement GetTypeElement(System.ComponentModel.ITypeDescriptorContext context, Mapper mapper)
        {
            if (context.PropertyDescriptor.Name.Contains("Source"))
                return mapper.MappingSource.TypeElement;

            return mapper.MappingDestination.TypeElement;

        }


    }
}
